FinDock Payment API

Current Version: v2

The FinDock Payment API is a REST API used to initiate online transactions and/or submit recurring payments to the FinDock application residing in a Salesforce Org. The API aims to abstract away both Salesforce and FinDock configuration details for specific payment processors and methods. The API instead provides several informational resources to retrieve environment-specific parameters of a particular Salesforce implementation. These resources can be used to make the front-end application environment and configuration agnostic.

Getting Started

If you are just starting to work with the API, please see:

Salesforce Objects, RecordTypes and Fields

Since our API is created for Salesforce implementations, there are some Salesforce-specific things to take into account. Alongside the primitive data types such as String, the Payment API uses several data types that might be unknown to you if you are not familiar with Salesforce or the Force.com platform. The data types that are only applied in Salesforce contexts are Salesforce Objects (sObjects) and Record Types and fields.

sObjects

sObjects are objects that can be stored in the (Sales)Force.com platform database. They are representations of data that persists in the Salesforce database. Some API resources accept, or even require, sObjects. The Payer object, for example, requires sObjects such as Contact and Account. The API allows you to define these objects in requests, as shown below, where both a Contact and an Account sObject are defined. FinDock objects like PaymentProfile can be used in the same way, but require you to specify the fields as Salesforce fields.

Example body of a request for creating a Contact and an Account sObject:

{
  "SuccessURL":"http://success.com",
  "FailureURL":"http://failure.com",
  "Payer":{
    "Contact":{
      "SalesforceFields":{
        "FirstName":"Eric",
        "LastName":"Johnson",
        "Email":"eric@johnson.com",
        "MailingStreet":"Rocket Rd",
        "MailingCity":"Hawthorne0",
        "MailingPostalCode":"CA 90250",
        "MobilePhone":"98989898"
      }
    },
    "Account":{
      "RecordTypeName: "Business",
      "SalesforceFields":{
        "Name":"Johnson Family",
        "Website":"www.spacex.com",
        "BillingStreet":"Rocket Rd",
        "BillingCity":"Hawthorne",
        "BillingPostalCode":"CA 90250"
      }
    }
  }
}

Record Types

Record types let Salesforce administrators offer different business processes, picklist values, and page layouts to different users. Organizations can, for example, differentiate between Account objects in Salesforce by assigning them either to the Record Type of Organization or Household. This facilitates the application of different types of page layouts or possible field values based on what Record Type an Account is. Your Salesforce Administrator can tell you more about the Record Types used in the Salesforce org.

Please note: when the Person Accounts feature is enabled in the environment Record Types are especially important. More information on Person Accounts can be found below.

Accounts, Contacts, Person Accounts

Salesforce provides two objects to indicate a Payer:

  • Account: usually an organisation
  • Contact: an individual

A Person Account stores information about individual people by combining certain account and contact fields into a single record. It is not its own object, but can be stored as an Account with a specific Record Type (see above). Some features of Salesforce - for instance Fundraising as used in NonProfit Cloud (NPC) - require an Account to be available. This means that when you have an individual payer you need to send a Person Account instead of a Contact. These features will only work with a Contact object when an Account object is also sent.

Make sure to always check with your Salesforce admin whether they are enabled and / or used!

To send Person Accounts to the FinDock API use an Account object with a RecordTypeName (API name) of a Record Type that is of the type Person Account. By default this is PersonAccount but there is a high chance this was customised or an environment has multiple Person Account Record Types, so always consult your Salesforce admin.

{
  "Account":{
    "RecordTypeName: "<a-person-account-record-type>",
    "SalesforceFields":{
      "Name":"Johnson Family",
      "Website":"www.spacex.com",
      "BillingStreet":"Rocket Rd",
      "BillingCity":"Hawthorne",
      "BillingPostalCode":"CA 90250"
    }
  }
}

Salesforce Fields

Next to the out-of-the-box Salesforce data model, Salesforce allows administrators to add custom fields to objects in Salesforce. All fields can be seen in the Salesforce Object Manager of the Salesforce org setup. Also, different implementations of Salesforce can use different fields for a value like email. The API allows you to send Salesforce fields, and their corresponding values, as attributes in requests to the API.

Custom fields for standard Salesforce objects like Contact and Account are passed with "__c" at the end. For illustration, we have added the standard fields FirstName and LastName and the custom field TwitterHandle to the Salesforce Contact object.

TwitterHandle | TwitterHandle__c | Text(50)

{
  "Payer":{
    "Contact":{
      "SalesforceFields":{
        "FirstName":"Eric",
        "LastName":"Johnson",
        "TwitterHandle__c": "@EricJohnsonSalesforce"
      }
    }          
  }
}

Custom fields for custom FinDock objects like Installment and Recurring Payment can also be passed in a SalesforceFields object. SalesforceFields passed in the OneTime object are copied to the Installment record in Salesforce and SalesforceFields passed in the Recurring object are copied to the Recurring object in Salesforce. What Recurring object the values are stored to depends on whether you use a Source Connector.

{
  "OneTime":{
    "Amount": 10.0,
    "SalesforceFields": {
      "Sales_Invoice__c": "a506E0000009TfL"
    }
  }
}

Exceptions

For Person Accounts the following exceptions for (custom) field notations apply:

  • Standard Account Fields can be passed as regular fields: "BillingStreet":"Rocket Rd".
  • Custom Account Fields can be passed with the regular __c suffix: "Custom_Street__c":"Rocket Rd".
  • Standard Contact Fields need to be prefixed with Person, with the exception of FirstName, LastName, Salutation which can be passed as regular fields: "PersonEmail" : "test@test.com".
  • Custom Contact Fields need to be suffixed with __pc: "Custom_email__pc":"test@test.com"

The fields and their correct notations can be found in the Salesforce Setup > Object Manager for Account.

Example:

{
  "Account":{
    "RecordTypeName: "PersonAccount",
    "SalesforceFields":{
      "FirstName":"John",
      "LastName":"Johnson",
      "PersonEmail":"test@test.com",
      "Website":"www.spacex.com",
      "BillingStreet":"Rocket Rd",
      "Custom_account_field__c":"Rocket Rd",
      "Custom_contact_field__pc":"Don't forget the P"
    }
  }
}

For the FinDock for Fundraising source connector used with NonProfit Cloud (NPC), for example, the following exception applies: Since the "Recurring" object (Gift Commitment) is split in two objects (Gift Commitment & Gift Commitment Schedule), a prefix GiftCommitment is required to set SalesforceFields on this object. Fields without prefix are assumed to be set on the Gift Commitment Schedule object. Example: GiftCommitment.GiftVehicle.

You can check which Source Connectors are available in the environment by performing a GET operation on the Source Connector endpoint.

Authentication

Authentication is accomplished through an Oauth2.0 authorization flow. Each Salesforce environment requires its own token. A refresh token can be used to acquire a new access token if the current token has expired. Read more on how to authenticate to Salesforce in the Salesforce developer guide. Both client_id and client_secret can be acquired from the Salesforce 'Setup' from a 'Connected App'.

  • The Authorization token can be passed as a Bearer token in the request Header.
  • To Acquire a new Authorization token with the returned Refresh token, please make sure to pass the right grant_type, client_id, client_secret and refresh_token as specified in the Salesforce documentation referenced above. To get up and running quickly, use the (unofficial-but-provided-by) Salesforce Postman Collection, as explained in this blog and look for the 'auth' folder.

Error and Response Codes

When the API was not called successfully, you will receive a HTTP Status Code 4xx or 500. Specifically a 422 code is returned when the message was well-formed, but could not be processed because of - for instance - wrong data. In the response you will find additional information on how to prevent or handle the error through an array of Errors with an error_code and error_message.

Example of a successful request (to the SourceConnector Provisioning API):

{
  "SourceConnectors": [
    {
      "Name": "PaymentHub",
      "PrettyName": "PaymentHub",
      "IsDefault": false
    }
  ]
}

Example of an error that is returned whenever an incorrect request is sent:

{
  "Errors": [
    {
      "error_message": "Amount can't be 0 or negative",
      "error_code": "020"
    }
  ]
}

Full list of possible response codes:

ResponseCodeDescription
010Malformed request: missing one or more mandatory core parameter(s)
011Malformed request: missing one or more mandatory Payment Processor parameters
012Malformed request: missing one or more mandatory SourceConnector parameters
200Invalid data: the supplied data is incorrect (e.g. an invalid e-mail address)
201Sort code or bank account invalid (Bacs Direct Debit)
202IBAN <your-iban> is not valid
203Provided IBAN is not in SEPA zone geographical scope
204BIC is required to collect SEPA Direct Debit from a non-EAA country bank account.
205Street, Housename or Number, Zip code and City are required to collect SEPA Direct Debit from a non-EEA country bank account.
206Clearing number and/or bank account invalid (Sweden)
098An object is missing and no default is specified
999Error without specific category: consult the error_message for details

For more information on errors and response codes and debugging the API, please see Troubleshooting the Payment API.

Webhook events / notifications

To receive updates on payments created with the /PaymentIntent endpoint:

  • pass an endpoint URL in the WebhookURL parameter in the request body.
  • add your URL to the Remote Site Setting of the Salesforce environment.

FinDock sends you notifications for the following events around your API call:

EventDescription
paymentIntent.createdWhen the processing of your API call has started in the Salesforce environment.
paymentIntent.processedWhen the processing of your API call has finished successfully. Note: this does not mean that the payment has been collected!
paymentIntent.in_reviewWhen the processing of your API call has stalled and manual intervention from Salesforce side has been requested. Note: this will not stop the customer from completing the payment flow!
paymentIntent.failedWhen the processing of your API call has failed and needs to be handled in the Salesforce environment. Note: this will not stop the customer from completing the payment flow!
installment.createdWhen an Installment (expected one-time payment) is created.
installment.status_changeIf the status of the One Time Payment (Installment record in Salesforce) changes, either by an update from a PSP or manually

No specific events are sent for recurring payments other than the paymentIntent which contains the Salesforce Id of the recurring record.

For more information about the processing of online payments, please Processing online payments.

Webhook content

For paymentIntent you will receive notifications with the following body. Each event contains a type and a data object with further details. Check out the PaymentIntent object description for definitions.

{
  "type": "paymentIntent.processed",
  "data": {
    "Status": "Matched",
    "Recurring": {
      "Url": "/services/data/v48.0/sobjects/cpm__Recurring_Payment__c/a0V3X00000S7b5YUAR",
      "Type": "cpm__Recurring_Payment__c",
      "Id": "a0V3X00000S7b5YUAR"
    },
    "Payer": {
      "Contact": {
        "Url": "/services/data/v48.0/sobjects/Contact/0033X00003H9uZPQAZ",
        "Type": "Contact",
        "Id": "0033X00003H9uZPQAZ",
        "Name": "Eric Johnson"
      },
      "Account": {
        "Url": "/services/data/v48.0/sobjects/Account/0013X00002bZPGIQA4",
        "Type": "Account",
        "Id": "0013X00002bZPGIQA4",
        "Name": "Johnson Family"
      }
    },
    "OneTime": {
      "Url": "/services/data/v48.0/sobjects/cpm__Installment__c/a083X00001mFTBAQA4",
      "Type": "cpm__Installment__c",
      "Id": "a083X00001mFTBAQA4",
      "Status": "Pending"
    },
    "Id": "pi_6cazikr7625yqt9mf"
  }
}

For installment you will receive a notification with the following body.

{
  "type": "installment",
  "data": {
    "Url": "/services/data/v48.0/sobjects/cpm__Installment__c/a083X00001kJynLQAS",
    "Type": "cpm__Installment__c",
    "Id": "a083X00001kJynLQAS",
    "Target": "Adyen1",
    "Status": "Collected",
    "RecordTypeName": "Receivable",
    "PayUrl": "https://link.dev.findock.com/pay/3xxxxmuai2/8897b4da-e48a-7ff3-90dd-ecb65094802c",
    "Payments": [
      {
        "Url": "/services/data/v48.0/sobjects/cpm__Payment__c/a0R3X00000V1sutUAB",
        "Type": "cpm__Payment__c",
        "Id": "a0R3X00000V1sutUAB",
        "PaymentProcessor": "PaymentHub-Adyen",
        "PaymentMethod": "CreditCard",
        "CollectionDate": "2020-11-26",
        "Amount": 15
      }
    ],
    "PaymentProcessor": "PaymentHub-Adyen",
    "PaymentMethod": "CreditCard",
    "PaymentIntentId": "pi_5jthokq7z8som0w6o",
    "AmountOpen": 0,
    "Amount": 15
  }
}

Servers

Was this page helpful?